`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/07/07 22:18:42
// Design Name: 
// Module Name: fetch
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


`define STARTADDR 32'd0     // 程序起始地址
module fetch(
    input           clk,        // 时钟
    input           resetn,     // 复位信号，低电平有效
    input           IF_valid,   // 取值有效信号
    input           next_fetch, // 取下一条指令
    input   [31:0]  inst,       // inst_rom取出的指令
    input   [32:0]  jbr_bus,     // 跳转总线
    output  [31:0]  inst_addr,  // 发往inst_rom的取值地址
    output  reg     IF_over,    // IF执行完毕
    output  [63:0]  IF_ID_bus,   // IF -> ID总线
    // 输出
    output  [31:0]  IF_pc,      // 下一个PC值
    output  [31:0]  IF_inst     // 实际取出的指令
    );

    wire [31:0] next_pc;
    wire [31:0] seq_pc;
    reg [31:0] pc;

    // 跳转PC
    wire jbr_taken;     // 跳转指令标识
    wire [31:0] jbr_target;     // 目标跳转指令
    assign {jbr_taken, jbr_target} = jbr_bus;   // 跳转总线

    assign seq_pc[31:2] = pc[31:2] + 1'b1;  // 下一条指令地址 pc = pc + 4;
    assign seq_pc[1:0] = pc[1:0];

    // 判断新指令是否为跳转指令
    assign next_pc = jbr_taken ? jbr_target : seq_pc;

    always @(posedge clk) 
    begin     // PC
        if (!resetn) 
        begin
            pc <= `STARTADDR;   // 复位
        end
        else if(next_fetch)
        begin
            pc <= next_pc;
        end
    end
    

    assign inst_addr = pc;

    always @(posedge clk)
    begin
        IF_over <= IF_valid;
    end

    assign IF_ID_bus = {pc, inst};

    assign IF_pc = pc;
    assign IF_inst = inst;

endmodule
